package cn.com.surker.handler;

import cn.com.surker.base.BaseEntity;
import cn.com.surker.base.system.dao.SysStorageLogDao;
import cn.com.surker.base.system.entity.SysLine;
import cn.com.surker.base.system.entity.SysStorageLog;
import cn.com.surker.control.entity.ControlExpend;
import cn.com.surker.control.entity.ControlExpendBatch;
import cn.com.surker.control.entity.ControlInvoice;
import cn.com.surker.control.service.ErpControlExpendBatchService;
import cn.com.surker.control.service.ErpControlExpendService;
import cn.com.surker.control.service.ErpControlInvoiceService;
import cn.com.surker.enums.StateEnum;
import cn.com.surker.enums.material.MaterialBreedTypeEnum;
import cn.com.surker.enums.production.car.CarWorkStatusEnum;
import cn.com.surker.enums.production.invoice.ControlProStatusEnum;
import cn.com.surker.enums.production.invoice.InvoiceProcessEnum;
import cn.com.surker.enums.production.invoice.PopEnum;
import cn.com.surker.lab.entity.LabExpend;
import cn.com.surker.lab.entity.LabExpendBatch;
import cn.com.surker.lab.entity.LabExpendOther;
import cn.com.surker.lab.entity.LabExpendUpload;
import cn.com.surker.lab.service.*;
import cn.com.surker.lab.vo.LabExpendOtherVo;
import cn.com.surker.production.entity.ProductionIndentDispatch;
import cn.com.surker.production.entity.ProductionInvoice;
import cn.com.surker.production.entity.ProductionManual;
import cn.com.surker.production.entity.vo.ProductionInvoiceVo;
import cn.com.surker.production.service.*;
import cn.com.surker.system.service.SysLineService;
import cn.com.surker.thread.ThreadPools;
import cn.com.surker.util.DateUtil;
import cn.com.surker.util.MathUtils;
import cn.com.surker.util.StringUtils;
import cn.com.surker.weight.service.ErpWeightOrderService;
import cn.com.surker.workcon.service.DosageService;
import cn.com.surker.workcon.service.ManualService;
import cn.com.surker.workcon.service.PieceService;
import cn.com.surker.workcon.service.ProductService;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import javax.annotation.Resource;
import javax.transaction.RollbackException;
import javax.validation.constraints.NotNull;
import java.util.*;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;

/**
 * 工控对接处理类,实际处理对接的方法
 * 本来方法不直接对外开放(因为要使用spring的框架,所以也不能更改方法权限)
 * 需要操作工控机数据时,未避免数据重复等请调用BCSStarter类
 *
 * @author luotao
 * @date 2024/11/6
 */
@Slf4j
@Component
public class BCSCoordinator {

	@Value("${erp.org.id}")
	private Long orgId;
	@Value("${erp.datasource.erp.db}")
	private String erpDb;

	@Value("${erp.datasource.ds.id}")
	protected Long dsId;
	@Value("${erp.datasource.org.name}")
	protected String orgName;

	//	发货单记录
	@Autowired
	private ErpInvoiceService invoiceService;
	//	派单记录
	@Autowired
	private ErpIndentDispatchService indentDispatchService;
	//	消耗盘记录
	@Autowired
	private ErpLabExpendBatchService expendBatchService;
	//	盘消耗记录
	@Autowired
	private ErpLabExpendService expendService;
	@Autowired
	private LabExpendUploadService labExpendUploadService;
	@Resource
	protected TranCarService tranCarService;
	//	工控机生产机
	@Resource
	private ProductService bcsProductService;
	//	工控机盘记录
	@Resource
	private PieceService pieceService;
	//	工控机消耗记录
	@Resource
	private DosageService dosageService;
	//	工控机手动消耗
	@Resource
	private ManualService manualService;

	@Resource
	private SysLineService sysLineService;
	@Resource
	private ErpLabExpendOtherService labExpendOtherService;

	@Autowired
	private ErpControlInvoiceService erpControlInvoiceService;

	@Autowired
	private ErpControlExpendBatchService erpControlExpendBatchService;

	@Autowired
	private ErpControlExpendService erpControlExpendService;

	@Resource
	private SysStorageLogDao sysStorageLogDao;
	@Autowired
	private ErpWeightOrderService erpWeightOrderService;

	//	手动生成发货单
	@Autowired
	private ProductionManualService productionManualService;




	/**
	 * 根据erp的派单id,查询工控机的发货单数据
	 *
	 * @param dispatchId erp的派单数据
	 */
	@Transactional(rollbackFor = RollbackException.class, propagation = Propagation.REQUIRED)
	public boolean convertInvoice(Long dispatchId) {
		if (dispatchId == null) {
			return false;
		}
		ProductionIndentDispatch dispatch = indentDispatchService.getById(dispatchId);
		if (!BaseEntity.validateExist(dispatch)) {
			return false;
		}
		//	判断是否已经处理
		Integer proStatus = dispatch.getProStatus();
		if (!InvoiceProcessEnum.QUERN_RECEIVE.getCode().equals(proStatus)
			&& !InvoiceProcessEnum.QUERN_PRO.getCode().equals(proStatus)
			&& !InvoiceProcessEnum.PRO.getCode().equals(proStatus)) {
			//	不为待接收状态
			return false;
		}
		Long lineId = dispatch.getLineId();
		//	1. 查询工控机数据
		ProductionIndentDispatch conDispatch = null;
		try {
			conDispatch = bcsProductService.queryByDispatchId(lineId, dispatchId);
		} catch (Exception e) {
			e.printStackTrace();
		}
		if (conDispatch != null) {
			//	验证状态
			Integer bacProFlag = conDispatch.getControlProStatus();
			if (bacProFlag == null) {
				return false;
			}
			//	生成方量
			Double prodMete = conDispatch.getProStere();
			//	生成时间
			Date prodTimE = conDispatch.getProTime();
			//	工控机的发货单id
			String prodId = conDispatch.getControlId();
			if (ControlProStatusEnum.AUTOMATIC.getCode().equals(bacProFlag)) {
				//	自动完成,处理发货单自动完成的情况
				compInvoice(dispatchId, prodId, prodMete, prodTimE, bacProFlag);
				return true;
			} else if (ControlProStatusEnum.MOVEMENT.getCode().equals(bacProFlag)) {
				//	手动生产,处理发货单手动生产的情况
				compInvoice(dispatchId, prodId, prodMete, prodTimE, bacProFlag);
				return true;
			} else if (ControlProStatusEnum.SEMI_AUTOMATIC.getCode().equals(bacProFlag)) {
				//	半自动生产完成,处理发货单半自动生产完成的情况
				compInvoice(dispatchId, prodId, prodMete, prodTimE, bacProFlag);
				return true;
			} else if (ControlProStatusEnum.INTERRUPT.getCode().equals(bacProFlag)) {
				//	生产中断完成,处理发货单生产中断完成的情况
				compInvoice(dispatchId, prodId, prodMete, prodTimE, bacProFlag);
				return true;
			} else if (ControlProStatusEnum.COMPLETED.getCode().equals(bacProFlag)) {
				//	整车数据已完整
				compInvoice(dispatchId, prodId, prodMete, prodTimE, bacProFlag);
				return true;
			} else {
				//	类型错误
				return false;
			}
		} else {
			return false;
		}
	}

	/**
	 * 查询工控机的消耗,并转换成erp的消耗类
	 *
	 * @param dispatchId erp的派单信息
	 * @param beSerial   盘的起始序列号,不包含本身
	 */
	// @Transactional(rollbackFor = RollbackException.class, propagation = Propagation.REQUIRES_NEW)
	public Boolean convertMaterial(Long dispatchId, Integer beSerial) {
		if (dispatchId == null) {
			return false;
		}
		//	查询erp的发货单
		ProductionIndentDispatch erpDisPatch = indentDispatchService.getById(dispatchId);
		if (erpDisPatch == null) {
			//	未查询到派单数据
			return false;
		}
		// 判断派单是否被删除,如果被删除了,则不需要操作,且返回成功
		Integer dispatchStatus = erpDisPatch.getStatus();
		if (!StateEnum.ENABLED.getCode().equals(dispatchStatus)) {
			log.info("派单处于被删除状态,不操作消耗数据:{}", JSONObject.toJSONString(erpDisPatch));
			return true;
		}
		//	生产线id
		Long lineId = erpDisPatch.getLineId();
		//	查询工控机的发货单信息(对应Product表)
		ProductionIndentDispatch conDispatch = bcsProductService.queryByDispatchId(lineId, dispatchId);
		if (conDispatch == null) {
			//	暂未查询出erp的发货单信息
			return false;
		}
		//	erp的发货单信息
		Long invoiceId = erpDisPatch.getInvoiceId();
		//	工控机的发货单id
		String prodId = conDispatch.getControlId();
		//	工控机的配合比编码
		String recipe = conDispatch.getRecipe();
		// 根据s生产线以及工控机的配合比编码,查询erp的配合比id,以及配合比的含水率
		Long formulaId = null;
		Double formulaWater = null;
		//	优化配合比
		Long levelOptimizeId = null;
		LabExpendUpload expendUpload = labExpendUploadService.queryByCode(lineId, recipe);
		if (expendUpload != null) {
			formulaId = expendUpload.getId();
			levelOptimizeId = expendUpload.getLevelOptimizeId();
		}
		Date createDate = new Date();
		//	查询下面的盘数据
		List<LabExpendBatch> pieceList = pieceService.findByProdId(lineId, invoiceId, prodId, beSerial, createDate);
		if (pieceList == null || pieceList.isEmpty()) {
			//	没有查询出消耗,不处理
			return false;
		}
		//	查询每盘的消耗
		for (int i = 0, s = pieceList.size(); i < s; i++) {
			//	将工控机的数据转换成erp的数据
			LabExpendBatch expendBatch = pieceList.get(i);
			if (expendBatch == null) {
				continue;
			}
			//	工控盘id
			String pieId = expendBatch.getConBatchId();
			//	判断erp中是否存在该盘的信息,如果存在,则取出旧信息,如果不存在,则新增
			List<LabExpendBatch> oldBatchs = expendBatchService.queryByInv(invoiceId, null, null);
			if (oldBatchs == null || oldBatchs.isEmpty()) {
				//	之前没有盘信息,直接保存第一盘
				expendBatch.setBatchNum(1);
				expendBatchService.save(expendBatch);
			} else {
				//	判断是否有旧数据
				LabExpendBatch oldBatch = oldBatchs.stream().filter(item -> {
					if (item.getConBatchId().equals(pieId) && item.getLineId().equals(lineId)) {
						return true;
					} else {
						return false;
					}
				}).findFirst().orElse(null);
				if (oldBatch == null) {
					//	之前存在旧数据,但是没有该盘的数据,判断是第几盘
					int batchNum = oldBatchs.size();
					batchNum += 1;
					expendBatch.setBatchNum(batchNum);
					expendBatchService.save(expendBatch);
				} else {
					expendBatch = oldBatch;
				}
			}
			//	erp盘id
			Long batchId = expendBatch.getId();
			// 盘消耗时间
			Date batTime = expendBatch.getBatchTime();
			//	盘方量
			Double batchStere = expendBatch.getBatchStere();
			//	根据盘id,查询盘的消耗记录
			List<LabExpend> dosageList = dosageService.findByPieId(lineId, invoiceId, batchId, prodId, pieId, batTime, batchStere, formulaId, formulaWater, levelOptimizeId, createDate);
			if (dosageList == null || dosageList.isEmpty()) {
				return false;
			}
			//	删除ERP上旧的消耗数据
			expendService.delByInvBatch(invoiceId, batchId, "自动同步消耗,更新删除");
			//	保存数据
			boolean b = expendService.saveBatch(dosageList);
		}
		return true;
	}

	/**
	 * 验证是否需要删除发货单单数据
	 *
	 * @param invoiceId 发货单id
	 */
	public void cancelInvoice(Long invoiceId, String remark) {
		List<ProductionIndentDispatch> dispatches = indentDispatchService.queryByInvoice(invoiceId);
		if (dispatches == null || dispatches.isEmpty()) {
			//	发货单下没有其他派单了,作废发货单,并更改车辆状态为等待
			ProductionInvoice invoice = invoiceService.getById(invoiceId);
			if (BaseEntity.validateExist(invoice)) {
				invoice.setProcess(InvoiceProcessEnum.DEL.getCode());
				invoice.addControlRemark(remark);
				invoice.setStatus(StateEnum.DISABLED.getCode());
				invoiceService.updateById(invoice);
				//	更改车辆状态
				@NotNull(message = "请选择运输车辆") Long carId = invoice.getCarId();
				tranCarService.updateStatus(orgId, carId, CarWorkStatusEnum.WAIT.getCode(), false, null);
			}
		}
	}


	/**
	 * 同步手动消耗数据
	 *
	 */
	public void convertManuale() {
		List<SysLine> sysLines = sysLineService.findAll();
		for (int i = 0, s = sysLines.size(); i < s; i++) {
			SysLine line = sysLines.get(i);
			try {
				//	查询最大的手动消耗时间
				Long lineId = line.getId();
				Date maxTime = labExpendOtherService.findMaxTime(lineId);
				List<LabExpendOther> gkManualList = manualService.findList(line, maxTime);
				if (gkManualList != null && gkManualList.size() > 0) {
					//	保存erp数据
					labExpendOtherService.saveBatch(gkManualList);
				}
			} catch (Exception e) {
				e.printStackTrace();
				continue;
			}
		}
	}

	/**
	 * 同步工控机的发货单
	 */
	@Transactional(rollbackFor = RollbackException.class, propagation = Propagation.REQUIRED)
	public List<ControlInvoice> syncControlInvoice() {
		List<SysLine> sysLines = sysLineService.findAll();
		Date nowDate = new Date();
		List<ControlInvoice> controlInvoices = null;
		for (SysLine sysLine : sysLines) {
			Long lineId = sysLine.getId();
			String lineName = sysLine.getName();
			//	查询erp中最大的id
			Date maxProTime = null;
			Long maxProId = erpControlInvoiceService.findMaxProId(lineId);
			if (maxProId == null) {
				maxProTime = erpControlInvoiceService.findMaxProTime(lineId);
			}
			//	查询工控机数据
			controlInvoices = bcsProductService.findFullByMin(lineId, lineName, maxProTime, maxProId);
			//	存入数据
			if (controlInvoices == null || controlInvoices.isEmpty()) {
				continue;
			}
			for (int i = 0, s = controlInvoices.size(); i < s; i++) {
				ControlInvoice controlInvoice = controlInvoices.get(i);
				//	查询erp是否存在该发货单数据
				String controlId = controlInvoice.getControlInvoiceNo();
				ControlInvoice oldData = erpControlInvoiceService.queryByConId(controlId);
				if (oldData != null) {
					// 存在旧数据,不操作
					continue;
				}
				//	查询erp的派单数据是否存在
				Long erpId = controlInvoice.getErpId();
				ProductionIndentDispatch erpDis = indentDispatchService.getById(erpId);
				if (!BaseEntity.validateExist(erpDis)) {
					//	没有数据
					controlInvoice.setConAuto(1);
				}
				//	保存工控数据
				erpControlInvoiceService.save(controlInvoice);
				Long invoiceId = controlInvoice.getId();
				//	查询材料数据
				List<ControlExpendBatch> expendBatches = pieceService.findByProdId(lineId, invoiceId, controlId, nowDate);
				//	存储盘数据
				if (expendBatches == null || expendBatches.isEmpty()) {
					continue;
				}
				//	查询盘数据下的消耗
				for (ControlExpendBatch expendBatch : expendBatches) {
					erpControlExpendBatchService.save(expendBatch);
					//	erp里面的盘号
					Long batchId = expendBatch.getId();
					//	工控机盘号
					String batchNo = expendBatch.getConBatchNo();
					//	下料时间
					Date batchTime = expendBatch.getBatchTime();
					//	查询盘下面的消耗数据
					List<ControlExpend> controlExpends = dosageService.findWorkByPieId(lineId, batchId, controlId, batchNo, batchTime, nowDate);
					erpControlExpendService.saveBatch(controlExpends);
				}
			}
		}
		System.err.println("同步工控机数据完成");
		return controlInvoices;
	}

	/**
	 * 处理发货单自动完成的情况
	 *
	 * @param dispatchId erp派单表id
	 * @param prodId     工控机的发货单id
	 * @param prodMete   工控机生产方量
	 * @param prodTimE   工控机生产时间
	 */
	private void compInvoice(Long dispatchId, String prodId, Double prodMete, Date prodTimE, Integer controlProStatus) {
		//	查询派单信息
		ProductionIndentDispatch dispatch = indentDispatchService.getById(dispatchId);
		if (!BaseEntity.validateExist(dispatch)) {
			return;
		}
		if (InvoiceProcessEnum.PRO_COMPLETE.getCode().equals(dispatch.getProStatus())) {
			return;
		}
		//	设置生产方量
		dispatch.setProStere(prodMete);
		dispatch.setProTime(prodTimE);
		dispatch.setProStatus(InvoiceProcessEnum.PRO_COMPLETE.getCode());
		//	设置派单表和工控机的关联数据
		dispatch.setControlId(prodId);
		dispatch.setControlProStatus(controlProStatus);
		indentDispatchService.updateById(dispatch);
		//	发货单id
		Long invoiceId = dispatch.getInvoiceId();
		//	1.查询发货单数据数据
		ProductionInvoice invoice = invoiceService.getById(invoiceId);
		//	查询发货单的生产方量
		// Double invProStere = indentDispatchService.queryInvProStere(invoiceId);
		//	发货单的发货数据为多个派单的累加
		//	生产时间采用工控机的生产截止时间
		Date invProTime = invoice.getProTime();
		if (invProTime == null) {
			invoice.setProTime(prodTimE);
		}
		//	发货方量默认生产方量
		// invoice.setSendStere(invProStere);
		//	签收方量默认生产方量
		// invoice.setSignStere(invProStere);
		//	设置为生产完成
		invoice.setProcess(InvoiceProcessEnum.PRO_COMPLETE.getCode());
		//	准备弹单
		invoice.setPopUp(PopEnum.REQUIRED.getCode());
		//	恢复发货单
		invoice.setStatus(StateEnum.ENABLED.getCode());
		//	更新发货单数据
		invoiceService.updateById(invoice);
		//	开始过磅
		ThreadPoolExecutor commonThreadPool = ThreadPools.getCommonThreadPool();
		commonThreadPool.execute(new Runnable() {
			@Override
			public void run() {
				//	查询发货单数据
				ProductionInvoiceVo invoiceVo = invoiceService.queryOverview(erpDb, orgId, invoiceId);
				erpWeightOrderService.beginWeight(orgId, orgName, dsId, invoiceVo, "砼生产过磅");
			}
		});
		//	更新车辆状态
		tranCarService.updateStatus(orgId, invoice.getCarId(), CarWorkStatusEnum.PRO_COMPLETE.getCode(), false, null);
	}

	/**
	 * 查询发货单没有仓位的消耗数据
	 *
	 * @param invoiceId
	 * @param startTime
	 * @param endTime
	 */
	public void syncInvoiceStorage(Long invoiceId, String startTime, String endTime) {
		//	查询生产线
		List<LabExpend> updateList = new ArrayList<>();
		//	查询erp上仓位为空的数据
		List<LabExpend> expendList = expendService.findSackStorageList(invoiceId, startTime, endTime);
		if (expendList == null || expendList.isEmpty()) {
			//	没有数据
			return;
		}
		//	根据生产线分组
		Map<Long, List<LabExpend>> lineExpends = expendList.stream().filter(e -> {
			if (e == null) {
				return false;
			}
			Long lineId = e.getLineId();
			if (lineId == null) {
				return false;
			}
			return true;
		}).collect(Collectors.groupingBy(LabExpend::getLineId));
		if (lineExpends == null || lineExpends.isEmpty()) {
			return;
		}
		Set<Long> lineIds = lineExpends.keySet();
		for (Long lineId : lineIds) {
			for (LabExpend labExpend : expendList) {
				try {
					//	获取工控机材料
					String controlMaterial = labExpend.getControlMaterial();
					//	如果没有材料,则从工控机取
					if (StringUtils.isBlank(controlMaterial)) {
						String conExpendId = labExpend.getConExpendId();
						Long batchId = labExpend.getBatchId();
						LabExpend conExpend = dosageService.queryByDosId(lineId, batchId, conExpendId);
						if (conExpend == null) {
							continue;
						}
						//	取出工控机的原材料
						controlMaterial = conExpend.getControlMaterial();
						labExpend.setControlMaterial(controlMaterial);
					}
					if (StringUtils.isBlank(controlMaterial)) {
						continue;
					}
					//	取出下料时间
					Date useTime = labExpend.getUseTime();
					if (useTime == null) {
						useTime = labExpend.getCreateTime();
					}
					//	查询料仓数据
					//	erp的原料id
					Long erpMaterialId = null;
					//	工控机的原料id
					Long erpStorageId = null;
					SysStorageLog takeTimeOrStorage = sysStorageLogDao.findTakeTimeOrStorage(lineId, controlMaterial, 1, DateUtil.convertString(useTime));
					if (takeTimeOrStorage != null) {
						erpMaterialId = takeTimeOrStorage.getMaterialId();
						erpStorageId = takeTimeOrStorage.getStorageId();
					}
					//	设置erp的材料id和仓位id
					labExpend.setMaterialId(erpMaterialId);
					labExpend.setStorageId(erpStorageId);
					updateList.add(labExpend);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
		expendService.updateBatchById(updateList);
	}

	/**
	 * 重新匹配发货单消耗
	 *
	 * @param invoiceId
	 */
	@Transactional(rollbackFor = RollbackException.class, propagation = Propagation.REQUIRED)
	public void delInvoiceExpend(Long invoiceId) {
		if (invoiceId == null) {
			return;
		}
		//	首先删除发货单下的盘和消耗
		expendBatchService.delByInv(invoiceId, "手动同步删除");
		//	查询消耗
		expendService.delByInvBatch(invoiceId, null, "手动同步删除");
	}

	/**
	 * 关联工控发货单到erp
	 */
	public void linkConInv2Erp(Long invoiceId, ControlInvoice controlInvoice) {
		//	先清空发货单原本的数据
		delInvoiceExpend(invoiceId);
		//	匹配数据
		Long erpControlId = controlInvoice.getId();
		//	工控机发货单号
		String controlNo = controlInvoice.getControlInvoiceNo();
		//	匹配盘数据
		List<ControlExpendBatch> expendBatchList = erpControlExpendBatchService.findList(erpDb, erpControlId);
		//	匹配消耗数据
		if (expendBatchList != null && expendBatchList.size() > 0) {
			for (int i = 0, s = expendBatchList.size(); i < s; i++) {
				ControlExpendBatch conBatch = expendBatchList.get(i);
				//	转换为erp的数据
				LabExpendBatch labExpendBatch = conBatch2Lab(invoiceId, controlNo, conBatch);
				if (labExpendBatch == null) {
					continue;
				}
				//	保存数据
				expendBatchService.save(labExpendBatch);
				//	erp数据的盘
				Long labBatchId = labExpendBatch.getId();
				//	工控数据盘
				Long conBatchId = conBatch.getId();
				//	查询工控消耗数据
				List<ControlExpend> controlExpendList = erpControlExpendService.findList(erpDb, conBatchId);
				//	转换数据
				List<LabExpend> LabExpendList = new ArrayList<>();
				if (controlExpendList != null && controlExpendList.size() > 0) {
					for (int a = 0, b = controlExpendList.size(); a < b; a++) {
						ControlExpend controlExpend = controlExpendList.get(a);
						LabExpend labExpend = conExpend2Lab(invoiceId, labBatchId, controlExpend);
						LabExpendList.add(labExpend);
					}
				}
				expendService.saveBatch(LabExpendList);
			}
		}
		//	更新工控机发货单信息
		controlInvoice.setLinkErp(1);
		erpControlInvoiceService.updateById(controlInvoice);
	}

	//	工控盘转换为erp盘
	private LabExpendBatch conBatch2Lab(Long invoiceId, String controlNo, ControlExpendBatch conBatch) {
		if (conBatch == null) {
			return null;
		}
		Integer batchNum = conBatch.getBatchNum();
		LabExpendBatch labExpendBatch = new LabExpendBatch();
		labExpendBatch.setInvoiceId(invoiceId);
		labExpendBatch.setLineId(conBatch.getLineId());
		labExpendBatch.setBatchNum(batchNum);
		labExpendBatch.setBatchStere(conBatch.getBatchStere());
		labExpendBatch.setBatchTime(conBatch.getBatchTime());
		labExpendBatch.setControlNo(controlNo);
		labExpendBatch.setConBatchId(conBatch.getConBatchNo());
		labExpendBatch.setConBatchNum(batchNum);
		labExpendBatch.setType(conBatch.getType());
		labExpendBatch.setStatus(StateEnum.ENABLED.getCode());
		labExpendBatch.setCreateTime(new Date());
		labExpendBatch.setCreator("关联同步");
		return labExpendBatch;
	}

	/**
	 * 工控数据转换为erp数据
	 *
	 * @param labBatchId
	 * @param controlExpend
	 * @return
	 */
	private LabExpend conExpend2Lab(Long invoiceId, Long labBatchId, ControlExpend controlExpend) {
		if (controlExpend == null) {
			return null;
		}
		//	匹配材料数据
		//	下料时间
		Date useTime = controlExpend.getUseTime();
		String batchTime = "";
		if (useTime != null) {
			batchTime = DateUtil.convertString(useTime);
		}
		//	工控机材料
		String bcsMaterial = controlExpend.getMaterial();
		//	s生产线
		Long lineId = controlExpend.getLineId();
		LabExpend labExpend = new LabExpend();
		labExpend.setInvoiceId(invoiceId);
		labExpend.setLineId(controlExpend.getLineId());
		labExpend.setMaterialId(controlExpend.getErpMaterialId());
		labExpend.setStorageId(controlExpend.getErpStorageId());
		labExpend.setControlStorage(controlExpend.getStorage());
		labExpend.setControlMaterial(bcsMaterial);
		labExpend.setBatchId(labBatchId);
		labExpend.setFormulaQuantity(controlExpend.getFormulaQuantity());
		labExpend.setControlSetQuantity(controlExpend.getControlSetQuantity());
		labExpend.setControlRealQuantity(controlExpend.getControlRealQuantity());
		labExpend.setControlWater(controlExpend.getControlWater());
		labExpend.setUseTime(useTime);
		labExpend.setConExpendId(controlExpend.getConExpendNo());
		labExpend.setStatus(StateEnum.ENABLED.getCode());
		labExpend.setCreateTime(new Date());
		labExpend.setCreator("关联同步");
		return labExpend;
	}

	public void syncBackStorage(Long invoiceId, String startTime, String endTime) {
		//	查询生产线
		List<LabExpend> updateList = new ArrayList<>();
		//	查询erp上仓位为空的数据
		List<LabExpend> expendList = expendService.findSackStorageList(invoiceId, startTime, endTime);
		if (expendList == null || expendList.isEmpty()) {
			//	没有数据
			return;
		}
		//	根据生产线分组
		Map<Long, List<LabExpend>> lineExpends = expendList.stream().filter(e -> {
			if (e == null) {
				return false;
			}
			Long lineId = e.getLineId();
			if (lineId == null) {
				return false;
			}
			return true;
		}).collect(Collectors.groupingBy(LabExpend::getLineId));
		if (lineExpends == null || lineExpends.isEmpty()) {
			return;
		}
		Set<Long> lineIds = lineExpends.keySet();
		for (Long lineId : lineIds) {
			for (LabExpend labExpend : expendList) {
				try {
					//	获取工控机材料
					String controlMaterial = labExpend.getControlMaterial();
					//	如果没有材料,则从工控机取
					if (StringUtils.isBlank(controlMaterial)) {
						String conExpendId = labExpend.getConExpendId();
						QueryWrapper<ControlExpend> qw = new QueryWrapper<>();
						qw.eq("con_expend_no", conExpendId);
						qw.eq("status", StateEnum.ENABLED.getCode());
						qw.last("limit 1");
						ControlExpend controlExpend = erpControlExpendService.getOne(qw);
						if (controlExpend == null) {
							continue;
						}
						//	取出工控机的原材料
						controlMaterial = controlExpend.getMaterial();
						labExpend.setControlMaterial(controlMaterial);
					}
					if (StringUtils.isBlank(controlMaterial)) {
						continue;
					}
					//	取出下料时间
					Date useTime = labExpend.getUseTime();
					if (useTime == null) {
						useTime = labExpend.getCreateTime();
					}
					//	查询料仓数据
					//	erp的原料id
					Long erpMaterialId = null;
					//	工控机的原料id
					Long erpStorageId = null;
					String takeTime = DateUtil.convertString(useTime);
					SysStorageLog takeTimeOrStorage = sysStorageLogDao.findTakeTimeOrStorage(lineId, controlMaterial, 1, takeTime);
					if (takeTimeOrStorage != null) {
						erpMaterialId = takeTimeOrStorage.getMaterialId();
						erpStorageId = takeTimeOrStorage.getStorageId();
					}
					//	设置erp的材料id和仓位id
					labExpend.setMaterialId(erpMaterialId);
					labExpend.setStorageId(erpStorageId);
					updateList.add(labExpend);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
		expendService.updateBatchById(updateList);
	}

	// @Transactional(rollbackFor = RollbackException.class, propagation = Propagation.REQUIRED)
	public void syncAllControl(String startTime, String endTime) {
		List<SysLine> sysLines = sysLineService.findAll();
		Date nowDate = new Date();
		List<ControlInvoice> controlInvoices = null;
		for (SysLine sysLine : sysLines) {
			Long lineId = sysLine.getId();
			String lineName = sysLine.getName();
			//	===========同步自动生产的============
			//	查询工控机数据
			controlInvoices = bcsProductService.findByTime(lineId, lineName, startTime, endTime);
			//	存入数据
			if (controlInvoices == null || controlInvoices.isEmpty()) {
				continue;
			}
			for (int i = 0, s = controlInvoices.size(); i < s; i++) {
				ControlInvoice controlInvoice = controlInvoices.get(i);
				//	查询erp是否存在该发货单数据
				String controlId = controlInvoice.getControlInvoiceNo();
				//	查询erp的派单数据是否存在
				Long erpId = controlInvoice.getErpId();
				//	查询是否有旧数据
				ControlInvoice oldInvoice = erpControlInvoiceService.queryByConId(controlId);
				if (oldInvoice != null) {
					// 存在旧数据,不操作
					controlInvoice = oldInvoice;
				} else {
					ProductionIndentDispatch erpDis = indentDispatchService.getById(erpId);
					if (!BaseEntity.validateExist(erpDis)) {
						//	没有数据
						controlInvoice.setConAuto(1);
					}
					//	保持旧数据
					erpControlInvoiceService.save(controlInvoice);
				}
				//	erp的工控发货单数据
				Long invoiceId = controlInvoice.getId();
				//	查询工控机的材料数据
				List<ControlExpendBatch> expendBatches = pieceService.findByProdId(lineId, invoiceId, controlId, nowDate);
				//	存储盘数据
				if (expendBatches == null || expendBatches.isEmpty()) {
					continue;
				}
				//	查询盘数据下的消耗
				for (ControlExpendBatch expendBatch : expendBatches) {
					//	工控机盘号
					String batchNo = expendBatch.getConBatchNo();
					//	查询是否有盘数据
					ControlExpendBatch oldBatch = erpControlExpendBatchService.queryByConNo(batchNo);
					if (oldBatch != null) {
						//	存在旧数据
						expendBatch = oldBatch;
					} else {
						//	保存新数据
						erpControlExpendBatchService.save(expendBatch);
					}
					//	erp里面的盘号
					Long batchId = expendBatch.getId();
					//	下料时间
					Date batchTime = expendBatch.getBatchTime();
					//	查询盘下面的消耗数据
					List<ControlExpend> controlExpends = dosageService.findWorkByPieId(lineId, batchId, controlId, batchNo, batchTime, nowDate);
					if (controlExpends == null || controlExpends.isEmpty()) {
						//	没有消耗
						continue;
					}
					//	删除消耗
					QueryWrapper<ControlExpend> qw = new QueryWrapper<>();
					qw.eq("erp_batch_id", batchId);
					qw.eq("status", StateEnum.ENABLED.getCode());
					// boolean remove = erpControlExpendService.remove(qw);
					//	查询该盘已有的消耗,移除已经有的消耗
					boolean b = false;
					List<ControlExpend> oldExpendList = erpControlExpendService.list(qw);
					if (oldExpendList != null && oldExpendList.size() > 0) {
						//	存在旧数据,判定是否存在
						List<ControlExpend> newList = new ArrayList<>();
						for (ControlExpend controlExpend : controlExpends) {
							boolean newData = true;
							for (ControlExpend oldExpend : oldExpendList) {
								//	盘id
								Long erpBatchId = controlExpend.getErpBatchId();
								//	工控消耗id编号
								String conExpendNo = controlExpend.getConExpendNo();
								//	工控数据
								Double controlRealQuantity = controlExpend.getControlRealQuantity();

								Long erpBatchId1 = oldExpend.getErpBatchId();
								String conExpendNo1 = oldExpend.getConExpendNo();
								Double controlRealQuantity1 = oldExpend.getControlRealQuantity();
								if (erpBatchId.equals(erpBatchId1) && conExpendNo.equals(conExpendNo1)) {
									//	判定为同一个
									newData = false;
									break;
								}
							}
							if (newData) {
								//	是新数据
								newList.add(controlExpend);
							}
						}
						if (newList.size() > 0) {
							b = erpControlExpendService.saveBatch(newList);
						} else {
							b = true;
						}
					} else {
						//	没有旧数据,直接保存消耗
						b = erpControlExpendService.saveBatch(controlExpends);
					}
					if (!b) {
						System.err.println(batchId);
					}
				}
			}
			//	===========同步手动生产的============
			List<LabExpendOther> gkManualList = manualService.findAllList(lineId, startTime, endTime);
			if (gkManualList != null && gkManualList.size() > 0) {
				//	查询数据是否存在
				//	删除时间段的数据并新增
				QueryWrapper<LabExpendOther> qw = new QueryWrapper<>();
				qw.ge("expend_time", startTime);
				qw.lt("expend_time", endTime);
				qw.eq("line_id", lineId);
				qw.eq("status", StateEnum.ENABLED.getCode());
				// boolean remove = labExpendOtherService.remove(qw);
				//	查询旧数据
				List<LabExpendOther> oldList = labExpendOtherService.list(qw);
				if (oldList == null || oldList.isEmpty()) {
					//	直接新增
					labExpendOtherService.saveBatch(gkManualList);
				} else {
					//	取出新数据
					List<LabExpendOther> newList = new ArrayList<>();
					for (int i = 0, s = gkManualList.size(); i < s; i++) {
						LabExpendOther labExpendOther = gkManualList.get(i);
						//	判定旧数据是否存在
						boolean newData = true;
						for (int a = 0, b = oldList.size(); a < b; a++) {
							LabExpendOther labExpendOther1 = oldList.get(a);
							Date expendTime = labExpendOther.getExpendTime();
							Double dosage = labExpendOther.getDosage();
							String controlStorage = labExpendOther.getControlStorage();
							//	消耗时间
							Date expendTime1 = labExpendOther1.getExpendTime();
							//	消耗值
							Double dosage1 = labExpendOther1.getDosage();
							//	工控仓位
							String controlStorage1 = labExpendOther1.getControlStorage();
							if (expendTime.equals(expendTime1) && dosage.equals(dosage1)
								&& controlStorage.equals(controlStorage1)) {
								newData = false;
								break;
							}
						}
						if (newData) {
							newList.add(labExpendOther);
						}
					}
					labExpendOtherService.saveBatch(newList);
				}
			}

		}
		System.err.println("全量同步工控机数据完成");
		return;
	}

	/**
	 * 根据手动消耗,匹配手动生产方量
	 */
	public void createHandInv() {
		//	先查询是否存在水泥消耗大于150的
		//	查询该记录前后5分钟石子等材料450的
		//	匹配该水泥消耗时间的之前且时间最接近的一车派单
		//	判定该派单的派单方量和生成方量是否存在差异
		//	如果存在差异,按照差异方量,生成一张手动创建的派单
		//	===================1===================
		//	查询一天内的数据
		Date nowDate = new Date();
		Date startDate = DateUtil.convertBeforeDayDate(nowDate, 1);
		String startTime = DateUtil.convertString(startDate);
		String endTime = DateUtil.convertString(nowDate);
		//	取出水泥大于100的消耗
		List<LabExpendOtherVo> allExpendList = labExpendOtherService.findFullList(startTime, endTime);
		if (allExpendList == null || allExpendList.isEmpty()) {
			//	没有手动消耗
			return;
		}
		//	待添加的手动生成数据
		List<ProductionManual> manualProList = new ArrayList<>();
		//	根据生产线分组
		Map<Long, List<LabExpendOtherVo>> lineMap = allExpendList.stream().collect(Collectors.groupingBy(LabExpendOtherVo::getLineId));
		Set<Long> lineIds = lineMap.keySet();
		for (Long lineId : lineIds) {
			List<LabExpendOtherVo> expendOtherList = lineMap.get(lineId);
			//	存储消耗时间以及对应的材料数据
			Map<String, String> handDataMap = new HashMap<>();
			// 第一遍遍历：识别触发点并计算删除范围
			for (int i = 0, s = expendOtherList.size(); i < s; i++) {
				LabExpendOtherVo labExpendOtherVo = expendOtherList.get(i);
				Integer breedType = labExpendOtherVo.getBreedType();
				if (MaterialBreedTypeEnum.GF.getCode().equals(breedType)) {
					Double dosage = labExpendOtherVo.getDosage();
					if (dosage != null && dosage > 150) {
						// 计算前后10条的范围
						int start = Math.max(0, i - 10);  // 防止越界
						int end = Math.min(s - 1, i + 10); // 防止越界
						// 计算用量总和
						double totalDosage = 0;
						List<Long> dosageIds = new ArrayList<>();
						for (int j = start; j <= end; j++) {
							LabExpendOtherVo childExpend = expendOtherList.get(j);
							Long id = childExpend.getId();
							dosageIds.add(id);
							Double d = childExpend.getDosage();
							if (d != null) {
								totalDosage += d;
							}
						}
						// 检查是否满足条件
						if (totalDosage > 1000) {
							//	消耗时间
							Date expendDate = labExpendOtherVo.getExpendTime();
							String expendTime = DateUtil.convertString(expendDate);
							String ids = JSONArray.toJSONString(dosageIds);
							handDataMap.put(expendTime, ids);
							//	设置下一次循环直接从最大值开始
							i = end;
						}
					}
				}
			}
			//	比较应该有派单的数据
			Set<String> handTimes = handDataMap.keySet();
			for (String handTime : handTimes) {
				//	查询距离该时间段最近的一个未删除派单,比较该派单的生产值和派单值
				QueryWrapper<ProductionIndentDispatch> disQw = new QueryWrapper<>();
				disQw.eq("status", StateEnum.ENABLED.getCode());
				disQw.lt("pro_time", handTime);
				disQw.orderByDesc("id");
				disQw.last("limit 1");
				List<ProductionIndentDispatch> dispatchList = indentDispatchService.list(disQw);
				if (dispatchList != null && dispatchList.size() > 0) {
					ProductionIndentDispatch dispatch = dispatchList.get(0);
					//	比较方量和数据
					//	上传方量
					Double uploadStere = dispatch.getUploadStere();
					//	生产方量
					Double proStere = dispatch.getProStere();
					Double diffStere = MathUtils.subtract(uploadStere, proStere);
					if (diffStere > 0) {
						//	对应的发货单
						Long dispatchId = dispatch.getId();
						Long invoiceId = dispatch.getInvoiceId();
						//	查询是否存在数据
						QueryWrapper<ProductionManual> qw = new QueryWrapper<>();
						qw.eq("status", StateEnum.ENABLED.getCode());
						qw.eq("pro_time", handTime);
						qw.eq("line_id", lineId);
						qw.last("limit 1");
						ProductionManual oldData = productionManualService.getOne(qw);
						if (oldData == null) {
							continue;
						}
						//	派单的旧方量
						//	取出对应的消耗id
						String expendIdList = handDataMap.get(handTime);
						//	表示有量差,直接补足
						ProductionManual productionManual = new ProductionManual();
						productionManual.setOrgId(orgId);
						productionManual.setLineId(lineId);
						productionManual.setInvoiceId(invoiceId);
						productionManual.setDispatchId(dispatchId);
						productionManual.setManualStere(diffStere);
						productionManual.setManulaIds(expendIdList);
						productionManual.setProTime(DateUtil.convertDate(handTime));
						productionManual.setOldStere(proStere);
						manualProList.add(productionManual);
					}
				}
				handDataMap.get(handTime);
			}
		}
		//	储存数据
		productionManualService.saveBatch(manualProList);
	}
}
